/*
* Copyright (C) 2012-2014 qar
* License: http://www.gnu.org/licenses/gpl.html GPL version 2
*/

#include "util.h"

#include <sys/ioctl.h>
#include <time.h>
#include <unistd.h>

#include "outputstream.h"

qint64 currentMSecsSinceEpoch()
{
#if (QT_VERSION >= QT_VERSION_CHECK(4, 7, 0))
    return QDateTime::currentMSecsSinceEpoch();
#else
    return (QDateTime().toTime_t() * 1000);
#endif
}

qint64 currentNanoSecsSinceEpoch()
{
    struct timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);
    return ts.tv_sec * 1000LL * 1000LL * 1000LL + ts.tv_nsec;
}

QString getLinkTarget(QString link)
{
    const int kBufferSize = 4096;
    char buffer[kBufferSize];

    int len = readlink(link.toLatin1().constData(), buffer, sizeof(buffer));

    if (len == -1) {
        return QString();
    } else {
        buffer[len] = '\0';
        return QString(buffer);
    }
}

QString getParentDir(QString path)
{
    QStringList items = path.split(QDir::separator());
    items.removeLast();
    return items.join(QDir::separator());
}

void addSizePrefix(qint64 &value, QString &prefix)
{
    prefix = "";
    if (value > 1024) {
        value /= 1024;
        prefix = "K";
    }
    if (value > 1024) {
        value /= 1024;
        prefix = "M";
    }
    if (value > 1024) {
        value /= 1024;
        prefix = "G";
    }
    if (value > 1024) {
        value /= 1024;
        prefix = "T";
    }
}

void displayProgress(QString currentItem,
                     qint64 currentProgressBytes,
                     qint64 startTime,
                     qint64 &lastProgressTime,
                     qint64 &lastProgressBytes,
                     const QIODevice *archiveFile)
{
    qint64 now = currentMSecsSinceEpoch();
    qint64 timeDelta = now - lastProgressTime;
    if (timeDelta < 1000) {
        return;
    }
    qint64 fileDelta = currentProgressBytes - lastProgressBytes;

    qint64 speed = (fileDelta * 1000) / timeDelta;
    QString unitPrefix;
    addSizePrefix(speed, unitPrefix);
    QString speedUnit = unitPrefix + "B/s";

    qint64 total = currentProgressBytes;
    addSizePrefix(total, unitPrefix);
    QString totalUnit = unitPrefix + "B";

    qint64 totalSpeed = (currentProgressBytes * 1000) / (now - startTime);
    addSizePrefix(totalSpeed, unitPrefix);
    QString totalSpeedUnit = unitPrefix + "B/s";

    QString ratio;
    if (archiveFile) {
        qint64 writtenBytes = archiveFile->size();
        qint64 writtenBytesApprox = writtenBytes;
        QString writtenBytesApproxUnit;
        addSizePrefix(writtenBytesApprox, writtenBytesApproxUnit);
        ratio = QString(" ratio %3%").arg((writtenBytes * 100) / qMax(1LL, currentProgressBytes));
    }

    int maxWidth = getTerminalWidth(STDERR_FILENO) - 45;
    if (currentItem.length() > maxWidth) {
        currentItem = currentItem.mid(0, maxWidth) + "...";
    }

    qErr().noSpace().noNewline() << "\33[2K\r";
    qErr().noSpace().noNewline() << speed << speedUnit << " (" <<
                                    total << totalUnit << " at " <<
                                    totalSpeed << totalSpeedUnit <<
                                    ratio << ") " <<
                                    currentItem << "\r";
    lastProgressTime = now;
    lastProgressBytes = currentProgressBytes;
}


int getTerminalWidth(int fd)
{
    struct winsize w;
    ioctl(fd, TIOCGWINSZ, &w);
    return w.ws_col ? w.ws_col : 80;
}
